<?php
/**
 * Main game engine calls
 *
 * @author Matt Pike
 */
class GameEng extends Controller{

#=== STARTUP ======================================================================================================
	/**
	 * Starts a battle if it hasn't yet been started
	 * Returns all player and unit info for the UI to load its first view
	 *
	 * @param array $request ['B'=BattleId, 'P'=PlayerId]
	 * @return NO RETURN. self::redirect("site.php?c=GameEng&a=loadFrontend&B=".$request['B']."&P=".$request['P']);
	 * B = StartedBattleId, P = CurrentPlayerId, SP = StartingPlayerId
	 */
	public static function startBattleAction(array $request){
		require_once(DirectoryManager::$pathModels."/battle/BattleCommand.php");

		//Start the Battle (If it hasn't been already!)
		$return = BattleCommand::Start($request);

		//Forward player to BattlePage (Units populated by pollInactiveTurnAction)
		self::redirect("site.php?c=GameEng&a=loadFrontend&B=".$return["B"]."&P=".$request['P']."&SP=".$return["SP"]);
	}

	/**
	 * Load game front end page or redirect if required to lobby/login
	 *
	 * @param $request ['P'=PlayerId, 'B'=BattleId]
	 * @return NO RETURN. return self::loadView("/game/game-frontend.phtml",array("playerId"=>$request["P"],"battleId"=>$request["B"]));
	 */
	public static function loadFrontendAction(array $request){
		$db = Database::getInstance();
		$schemaVersion = $db->getSchemaVersion();
		if($schemaVersion != SiteConfig::schemaVersion){
	 		throw new Exception("WARNING: Schema is outdated! Expecting version '" . SiteConfig::schemaVersion . "' found version '" .$schemaVersion,1209145);
	 	}
	 	if(!isset($request["B"]) || !is_numeric($request["B"])){
	 		throw new InvalidArgumentException("Invalid Battle Id", 1298312);
	 	}
		//if(user is logged in and game exists){
			return self::loadView("/game/game-frontend.phtml",array("playerId"=>$request["P"],"battleId"=>$request["B"]));
		//}else{
		//	redirect to login/lobby
		//}
	}

	/**
	 * Connects a Player to their Game byt returning all startup info
	 * Essentially a snapshot of the entire battle
	 *
	 * @param array $request ['B'=BattleId]
	 * @return array $return
	 * $return = array(
	 *		"players" => $allPlayerRows,
	 *		"units" => $allUnitRows,
	 *		"chat" => array(
	 *			array("p"=>2,"msg"=>htmlentities("hello world ".rand(0,99)))
	 *		)
	 *	);
	 */
	public static function connectToGameAction(array $request){
		require_once(DirectoryManager::$pathModels."/battle/BattleCommand.php");

		//Fetch All data =======================================================
		$ts = 1262304000; //HARDCODED BASE TimeStamp (01/01/2010 00:00:00)
		$params = array("B"=>$request['B'], "ts"=>$ts); //Add new BASE Ts to the params array
		$allUnitRows = BattleCommand::GetUpdates($params);
		$allPlayerRows = BattleCommand::GetPlayersInfo($params);

		//Convert to return friendly array ======================================
		$return = array(
			"players" => $allPlayerRows,
			"units" => $allUnitRows,
			"chat" => array(
				array("p"=>2,"msg"=>htmlentities("hello world ".rand(0,99)))
			)
		);
		return $return;
	}




#=== POLLING ======================================================================================================
	/**
	 * -INACTIVE- PLAYERS ONLY: Poll for any game updates since the last server timestamp
	 *
	 * @param array $request ['B'=BattleId, 'ts'=LastServer TimeStamp Polled]
	 * @return array $polledData
	 * $polledData = array(
	 *		"ts" => $allAlteredRows[0]["ts"],
	 *		"moves" => $allAlteredRows,
	 *		"chat" => array("p"=>2,"msg"=>htmlentities("hello world ".rand(0,99)))
	 *	);
	 */
	public static function pollInactiveTurnAction(array $request){
		require_once(DirectoryManager::$pathModels."/battle/BattleCommand.php");

		//TODO Check all players still active
		//TODO Add battle events, hacking etc here to occupy player off turn

		//Fetch all rows which have been altered since the last poll timestamp(ts)
	 	$allAlteredRows = BattleCommand::GetUpdates($request);

	 	//Fetch Chat
	 	//TODO Check for chat updates? Example: $return[] = array("typ"=>"chat","msg"=>"fun fun fun")

	 	//Merge all polled data for return
	 	//TODO discuss new codes for return
	 	$polledData = array(
	 	"ts" => $allAlteredRows[0]["ts"],
	 	"moves" => $allAlteredRows,
	 	"chat" => array("p"=>2,"msg"=>htmlentities("hello world ".rand(0,99)))
	 	);

	 	//print_r($polledData);
	 	return $polledData;
	}

	/**
	 * -ACTIVE- PLAYERS ONLY: Poll for any game updates since the last server timestamp
	 *
	 * @param array $request ['B'=BattleId]
	 * @return array $polledData
	 * $polledData = array(
	 *		"ts" => $ts,
	 *		"chat" => array("p"=>2,"msg"=>htmlentities("hello world ".rand(0,99)))
	 *	);
	 */
	public static function pollActiveTurnAction(array $request){
		require_once(DirectoryManager::$pathCore."/Database.php");

		//TODO Check all players still active
	 	//TODO Check for chat updates? Example: $return[] = array("typ"=>"chat","msg"=>"fun fun fun")
		//TODO Fetch Hacking Updates?

		// Fetch latest server ts =====================================================
		$ts = Database::querySingle("SELECT UNIX_TIMESTAMP(NOW());");

		// Convert to return friendly =================================================
		$polledData = array(
	 		"ts" => $ts,
	 		"chat" => array("p"=>2,"msg"=>htmlentities("hello world ".rand(0,99)))
	 	);

	 	// Return =====================================================================
	 	return $polledData;
	}




#=== BATTLE ACTIONS ================================================================================================
	/**
	 * End a players turn. Returns the new active players Id or -1 in the event of failure!
	 * UI Should start polling poll-Inactive-TurnAction immediately after this Action returns
	 *
	 * @param array $request ['B'=BattleId, 'P'=PlayerId]
	 * @return array $return
	 * SUCCESS = ['P'=NewActivePlayerId]
	 * FAILURE = -1
	 */
	public static function endPlayerTurnAction(array $request){
		require_once(DirectoryManager::$pathModels."/battle/BattleCommand.php");
		$return = BattleCommand::EndTurn($request);
		return $return;
	}




#=== UNIT ACTIONS ==================================================================================================
	/**
	 * Performs a unit move
	 *
	 * @param array $request ['U'=UnitId, 'x'=newXCoord, 'y'=newYCoord, 'r'=newRotation]
	 * @return array $result
	 * SUCCESS = ['U'=UnitId, 'mp'=RemainingMovementAP]
	 * FAILURE = -1
	 */
	public static function unitMoveAction(array $request){
		require_once(DirectoryManager::$pathModels."/unit/Unit_Base.php");
		require_once(DirectoryManager::$pathModels."/unit/Unit_1T.php");

		#TODO Finish coding unitMoveAction!
		# Add code to determine unit type which is moving. Suppose this should be part of the $request...
		# HARDCODED - For now we are assuming an Agile Unit_1T movement!

		# Make request to DB
		$result = Unit_1T::Move($request);

		# Convert to return friendly
		#TODO Finish coding unitMoveAction!

		# Return
		return $result;
	}

	/**
	 * Performs a unit attack
	 *
	 * @param array $request ['U'=Firing UnitId, 'W'= WeaponId, 'x'=Target coord X, 'y'=Target coord Y, 'TU'=TargetUnit Id]
	 * @return array $affectedUnits [All rows affected by the attack, including the attacker]
	 */
	public static function unitAttackAction(array $request){
		require_once(DirectoryManager::$pathModels."/unit/Unit_Base.php");
		require_once(DirectoryManager::$pathModels."/unit/Unit_1T.php");

		#TODO Think about adding experience gain inside the Attack SPs
		$affectedUnits = Unit_1T::Attack($request);
		return $affectedUnits;
	}



















// ===== LOTS OF OLD COMMENTED CRAP I DON'T WANT TO DELETE JUST YET ============================================================
//	/**
//	 * Polled method to check for general game updates and events
//	 *
//	 * @param array $request
//	 * @return string
//	 */
//	public static function checkForUpdatesAction(array $request){
//		require_once(DirectoryManager::$pathModels."/battle/BattleCommand.php");
//
//		// Check all players still active
//		// Add battle events, hacking etc here to occupy player off turn
//
//		//Fetch all rows which have been altered since the last poll timestamp(ts)
//	 	$allAlteredRows = BattleCommand::GetUpdates($request);
//
//	 	//Fetch Chat
//	 	// Check for chat updates? Example: $return[] = array("typ"=>"chat","msg"=>"fun fun fun")
//
//	 	//Merge all polled data for return
//	 	// discuss new codes for return
//	 	$polledData = array(
//	 	"ts" => $allAlteredRows[0]['ts'],
//	 	"moves" => $allAlteredRows,
//	 	"chat" => array("p"=>2,"msg"=>htmlentities("hello world ".rand(0,99)))
//	 	);
//
//	 	return $polledData;
////############ OLD CODE ####################################################
////		$return = array(
////				"ts" => time(),
////				"moves" => array(
////					// #=id,p=player,r=rotation, t=team (so we can hav different races later), ap = action points (is that the right term for move points?), mt = movement type (how ships behave, perhapps when smaller agile ships get damaged we could change the movement type on them to act like capships)
////					array("id"=>"8","x"=>5,"y"=>rand(0,2),"r"=>180),
////					array("id"=>"9","x"=>7,"y"=>1,"r"=>135),
////					array("id"=>"10","x"=>3,"y"=>1,"r"=>225),
////					// $ship1->toArray() <- just one way u might want to do it, you would need to write the toArray method tho
////				),
////				"chat" => array(
////					array("p"=>2,"msg"=>htmlentities("hello world ".rand(0,99)))
////				)
////				//,"debug" => "this is debug code just for marc. see checkForUpdatesAction()"
////		);
////		// if(NOT players turn){
////		// 		$newMoves = Map::checkForMovesFlaggedAsNew(player Id);
////		//		foreach($newMoves as $move){
////		//			$return[] = array(
////		//				"typ" 	=> "move",
////		//				"unitId"=> $move->unitId,
////		//				"x"		=> $move->x,
////		//				"y"		=> $move->y,
////		//				"rot"	=> $move->bearing
////		//			);
////		//		}
////		// }
////		//
////		return json_encode($return);
//	}




//	/**
//	 * Return all info required to initialise game
//	 *
//	 * @param array $request
//	 * @return string
//	 */
//	public static function connectToGame_OLD_Action(array $request){
//		require_once(DirectoryManager::$pathModels."/unit/Unit_Base.php");
//		require_once(DirectoryManager::$pathCore."/Database.php");
//		require_once(DirectoryManager::$pathUnitTests."/defaults/Default_Battle.php");
//		//usleep(2000000); // heavy load test
//
//		//HARDCODED: 	Create new battle instance for PlayerId 0 & 1
//		//				Includes default staring units
//
//		$request = array("SP"=>1,"P1"=>1, "P2"=>2, "PT1"=>1, "PT2"=>2);
//		$allUnitRows = Default_Battle::CreatePreset2PlayerBattle($request);
//
//		return $allUnitRows;
//
//
////		// == OLD INIT CODE SAMPLE ==
////		$return = array(
////			"players" => array(
////				array("id"=>1, "name"=>"Matt","team"=>1),
////				array("id"=>2, "name"=>"Marc","team"=>2)
////				),
////			"units" => array(
////				// #=id,p=player,r=rotation, t=team, ap = action points (is that the right term for move points?), mt = movement type (how ships behave, perhapps when smaller agile ships get damaged we could change the movement type on them to act like capships)
////				array("typ"=>"shuttle1","id"=>"0","p"=>1,"t"=>1,"x"=>4,"y"=>4,"r"=>315,"ap"=>2,"mt"=>GameConfig::movementType_agile),
////				// array("typ"=>"corvette1","id"=>"fox4","p"=>1,"t"=>1,"x"=>3,"y"=>5,"r"=>270,"ap"=>2,"mt"=>GameConfig::movementType_heavy),
////				// PLAYER 2
////				array("typ"=>"shuttle1","id"=>"8","p"=>2,"t"=>1,"x"=>5,"y"=>1,"r"=>180,"ap"=>2,"mt"=>GameConfig::movementType_agile)
////			)
////		);
////		// $ship1->toArray() <- just one way u might want to do it, you would need to write the toArray method tho
////		return $return;
//	}
}